<?php
/**
 * Объек для внутреннего использования внутри модуля
 * управление авторизацией
 */
class mauth_control
{
    private $cfg;
    private $cache_methods;
    /**
     * Запускает сессию, если пользователь авторизован
     * @return number
     */
    function auth()
    {
        // Проверка авторизации
        // Стартуем сессию, если она была ранее 
        // запущена для пользователя
        mauth_util_ifsession_start();
        return mauth_this_isauth();
    }

    /**
     * Вход пользователя
     * @param $wholelogin
     * @param $password
     * @return void
     */
    function login($wholelogin,$password)
    {
        // Вход пользователя
        if ($this->auth() or empty($password))
        {
            // Пользователь уже авторизован
            return false;
        }
        // Преобразуем логин
        // $wholelogin = mauth_util_locallogin($wholelogin);
        // Ищем пользователя в базе
        $userinfo = $this->searchuser($wholelogin,$password,false);
        if ($userinfo['pass'] !== true)
        {
            // Авторизация не удалась
            return false;
        }
        // Если нужно, ищем id 
        $id = false;
        if ($this->cfg['id']
        AND $userinfo['method']===$this->cfg['idmethod']
        AND $userinfo['id'] > 0)
        {
            // Мы должны получить id от текущего метода авторизации
            $id = $userinfo['id'];
        }elseif ($this->cfg['id']
        AND ($out_id = $this->searchuserid($wholelogin))!== false)
        {
            // Получаем id из другого метода
            $id = $out_id;
        }

        if ($this->cfg['id'] and $id === false)
        {
            // Id требуется, но не найден
            mst_error('Сбой при получении id',
			"Невозможно получить id, включенный в настройках авторизации",1);
        }
        // Преобразуем логин в необходимый вид
        $setwholelogin = mauth_util_loginreduct($wholelogin,
                                $this->cfg['sesslogin']['localhost'],
                                $this->cfg['sesslogin']['realhost'],
                                $this->cfg['sesslogin']['hostreduct'],
                                $this->cfg['sesslogin']['hostonly'],
                                $this->cfg['sesslogin']['hostempty']);
        // Пишем авторизацию в сессию
        $this->setuser($setwholelogin,$userinfo['method'],$id);
        return true;
    }

    /**
     * Вход пользователя от имени другого пользователя
     */
    function loginsu($wholelogin)
    {
        // Преобразуем логин
        // $wholelogin = mauth_util_locallogin($wholelogin);
        // Ищем пользователя в базе
        $userinfo = $this->searchuser($wholelogin,false,true);
        if (!$userinfo['exist'])
        {// print_r($userinfo);
            return false;
        }
        // Ищем id
        $id = false;
        if ($this->cfg['id']
        AND $this->cfg['idmethod']===$userinfo['method']
        AND $userinfo['id'] > 0)
        {
            // Мы должны получить id от текущего метода авторизации
            $id = $userinfo['id'];
        }elseif ($this->cfg['id']
        AND ($out_id = $this->searchuserid($wholelogin))!== false)
        {
            // Получаем id из другого метода
            $id = $out_id;
        }elseif ($this->cfg['id'])
        {
            // Id требуется, но не найден
            mst_error('Сбой при получении id',
			"Невозможно получить id, включенный в настройках авторизации",1);
        }
       // Преобразуем логин в необходимый вид
        $setwholelogin = mauth_util_loginreduct($wholelogin,
                                $this->cfg['sesslogin']['localhost'],
                                $this->cfg['sesslogin']['realhost'],
                                $this->cfg['sesslogin']['hostreduct'],
                                $this->cfg['sesslogin']['hostonly'],
                                $this->cfg['sesslogin']['hostempty']);
        return $this->setsuuser($setwholelogin,$id);
    }

    /**
     * Выход пользователя
     * @return bool
     */
    function logout($unset_all=false)
    {
        $this->unsetuser($unset_all);
        return true;
    }
    
    /**
     * Выход из su
     */
    function logoutsu()
    {
        return $this->unsetsuuser();
    }

    /**
     * Установить пользователя в сессию
     */
    private function setuser($wholelogin,$method,$id = null)
    {
        // Устанавливаем сессию для пользователя
        mauth_util_session_start();
        $user = mauth_util_explwhole($wholelogin);
        $_SESSION['mauth']['user']['auth'] = true;
        $_SESSION['mauth']['user']['sudo'] = false;
        $_SESSION['mauth']['user']['time'] = time();
        $_SESSION['mauth']['user']['method'] = $method;
        $_SESSION['mauth']['user']['real']['login']=$user['login'];
        $_SESSION['mauth']['user']['real']['host']=$user['host'];
        $_SESSION['mauth']['user']['real']['id']=null;
        $_SESSION['mauth']['user']['this']['login']=$user['login'];
        $_SESSION['mauth']['user']['this']['host']=$user['host'];
        $_SESSION['mauth']['user']['this']['id']=null;
        if (!is_null($id))
        {
            // Устанавливаем id, если нам его передеал
            $_SESSION['mauth']['user']['real']['id']=$id;
            $_SESSION['mauth']['user']['this']['id']=$id;
        }
        return true;
    }

    /**
     * Установить вход от имени в сессию
     */
    private function setsuuser($wholelogin,$id=null)
    {
        // Проверяем авторизацию
        if (!$this->auth())
        {
            // Пользователь не авторизован
            return false;
        }
        // Выполняем su для пользовател
        $user = mauth_util_explwhole($wholelogin);
        $_SESSION['mauth']['user']['this']['login']=$user['login'];
        $_SESSION['mauth']['user']['this']['host']=$user['host'];
        $_SESSION['mauth']['user']['sudo'] = true;
        if (!is_null($id))
        {
            // Устанавливаем id, если нам его передеал
            $_SESSION['mauth']['user']['this']['id']=$id;
        }
        return true;
    }

    /**
     * Удалить вход от имени из сессии
     */
    private function unsetsuuser()
    {
        // Возвращаемся к исходному пользователю
        if (!$this->auth())
        {
            // Пользователь не авторизован
            return false;
        }
        $_SESSION['mauth']['user']['this']['login'] =
        $_SESSION['mauth']['user']['real']['login'];
        $_SESSION['mauth']['user']['this']['host'] =
        $_SESSION['mauth']['user']['real']['host'];
        $_SESSION['mauth']['user']['sudo'] = false;
        if (!is_null($_SESSION['mauth']['user']['real']['id']))
        {
            // Устанавливаем id, если нам его передеал
            $_SESSION['mauth']['user']['this']['id']=
            $_SESSION['mauth']['user']['real']['id'];
        }
        return true;
    }

    /**
     * Удалить пользователя из сессии
     */
    private function unsetuser($unset_all=false)
    {
        // Стартуем сессию, если она была ранее 
        // запущена для пользователя
        if (!$this->auth())
        {
            // Пользователь не авторизован
            return false;
        }
        // Заканчиваем авторизаци
        unset($_SESSION['mauth']['user']);
        if ($unset_all)
        {
            session_unset();
        }
        return true;
    }

    //*******************************************
    /**
    * Поиск пользователя
    * возвращает массив с ключами
    * pass = true, если пароль верный
    * id - id пользователя в его корневом методе (если поддерживаются)
    * exist = true, если пользователь существует
    * method - метод, в котором найден пользователь
    * @param $wholelogin
    * @param $password
    * @return array
    */
    function searchuser($wholelogin,$password='',$existcheck = false)
    {
        $result = array('id'=>false,'pass'=>false,'exist'=>false,'method'=>null);
        // Преобразуем логин
        // $wholelogin = mauth_util_locallogin($wholelogin);
        // Просматриваем методы авторизации
        $methods_cfg = $this->cfg['methods'];
        foreach($methods_cfg as $method => $method_cfg)
        {
            // Преобразуем логин для этого метода
            $methodwholelogin = mauth_util_loginreduct($wholelogin,
                                            $method_cfg['localhost'],
                                            $method_cfg['realhost'],
                                            $method_cfg['hostreduct'],
                                            $method_cfg['hostonly'],
                                            $method_cfg['hostempty']);
            if ($methodwholelogin===false)
            {
                // Такой логин в этом методе запрещен
                break;
            }
            // Загружаем метод авторнизации
            $AuthMethod = $this->loadmethod($method);
            if (!is_a($AuthMethod,'mauth_checkuser'))
            {
                mst_error('Не подключен метод авторизации',
					"Ошибка при подключении метода авторизации '{$method}'",1);
                break;
            }
            // Проверяем логин и пароль
            if ($AuthMethod->auth($methodwholelogin,$password))
            {
                // Авторизация подтверждена
                $result['pass'] = true;
                $result['exist'] = true;
                $result['id'] = false;
                $result['method'] = $AuthMethod->method();
                if ($AuthMethod->isuserid())
                {
                    // Id поддерживается текущим методом
                    $result['id'] = $AuthMethod->getthisuserid();
                }
                // Пишем в сессию авторизацию
                break;
            }elseif ($existcheck)
            {
                // Если авторизация не прошла, но затребована еще и проверка существования
                // Проверяем наличие пользователя в этом методе
                if ($userinfo = $AuthMethod->getuserinfo($methodwholelogin))
                {
                    $result['pass'] = false;
                    $result['exist'] = true;
                    $result['id'] = false;
                    $result['method'] = $AuthMethod->method();
                    if ($AuthMethod->isuserid())
                    {
                        // Id поддерживается текущим методом
                        $result['id'] = $userinfo['id'];
                    }
                }
                break;
            }
        }
        return $result;

    }

    /**
     * Возвращает id пользователя из метода, ответственного за id в настройках
     * @param $wholelogin
     * @return int
     */
    function searchuserid($wholelogin)
    {
        $id = false;
        if (!$this->cfg['id'])
        {
            // id не поддерживаются
            return false;
        }
        // Настройки метода для преобразования домена
        if ($this->cfg['idmethod_cfg'])
        {
            // Для id создана отдельная конфигурация
            $method_cfg = $this->cfg['idmethod_cfg'];
        }else
        {
            // Для id используем общую конфигурацию
            $method_cfg = $this->cfg['methods'][($this->cfg['idmethod'])];
        }
        // Преобразуем логин для этого метод
        $methodwholelogin = mauth_util_loginreduct($wholelogin,
                                $method_cfg['localhost'],
                                $method_cfg['realhost'],
                                $method_cfg['hostreduct'],
                                $method_cfg['hostonly'],
                                $method_cfg['hostempty']);
        if ($methodwholelogin===false)
        {
            // Такой логин в этом методе запрещен
            break;
        }
        
       // Получаем метод авторизации, через который ищем id
        $IdMethod = $this->loadmethod($this->cfg['idmethod'],$this->cfg['idmethod_cfg']);

        if (!is_a($IdMethod,'mauth_checkuser'))
        {
            mst_error('Не подключен метод авторизации',
			"Ошибка при подключении метода авторизации '".$this->cfg['idmethod']."'",1);
            return false;
        }
        if (!$IdMethod->isuserid())
        {
            mst_error('Метод авторизации не поддерживает id',
			"Невозможно получить id с помощью метода  '".$this->cfg['idmethod']."' "
			." так как он не поддерживает id",1);
			return false;
        }
        // Ищем id
        if (!($id = $IdMethod->getuserid($methodwholelogin))
        AND $this->cfg['idreg']
        AND $IdMethod->isreg())
        {
            // Регистрируем пользователя и возвращаем id
            $id = $IdMethod->reguser($methodwholelogin);
        }elseif (!$id)
        {
            // id не найден, а регистрация запрещена
            mst_error('Сбой при получении id',
			"id не найден, а регистрация запрещена (или не поддерживается методом авторизации)",1);
            return false;
        }
        return $id;
    }

    private function loadmethod($method,$method_cfg=false)
    {
        if (!mst_util_nodirs($method))
        {
            mst_error('Неправильное имя метода авторизации', 
			"Имя метода авторизации '{$method}' содержит недопустимые символы",1);
            return false;
        }
        // Если конфигурацию не передали явно - получаем из настроек
        if ($method_cfg === false)
        {
            // Ищем метод в кеше
            if (isset($this->cache_methods[$method]))
            {
                return $this->cache_methods[$method];
            }
            $method_cfg = $this->cfg['methods'][$method];
        }
        // Проверяем существование файла с классом метода
        if ($method_path = mst_modpath('mauth',"methods/{$method}.php",true))
        {
            include_once $method_path;
            $method_class = 'mauth_checkuser_'.$method;
            if (class_exists($method_class))
            {
                // Класс метода определен
                $AuthMethod = new $method_class($method_cfg);
                // Кешируем метод
                if ($method_cfg === false)
                {
                        $this->cache_methods[$method] = $AuthMethod;
                }
                return $AuthMethod;
            }
        }
        mst_error('Не подключен метод авторизации',
			"Ошибка при подключении метода авторизации '{$method}'"
        ." не найден файл '{$method_path}'",1);
        // Файл класса отсутствует
        return false;
    }

    /**
     * Конструктор
     */
    function __construct($cfg)
    {
        //
        $this->cfg = $cfg;
        // Обнуляем кеш методов
        $this->cache_methods = array();
    }
}
?>